package com.momoauth.common.security.aspect;

import com.momoauth.common.security.annotation.ValidateRepeatSubmit;
import com.momoauth.common.core.exception.GlobalException;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Aspect
@Order(0)
public class ValidateRepeatSubmitAspect {

    /**
     * 其实在网关层已实现限流策略，但为了更灵活、更进一步地进行限流措施，
     * 这里提供用于方法内的注解来解决某些接口方法需短时间内避免重复提交的问题，
     * 但需要注意判断重复点击的触发条件要小于网关层的触发条件，否则没有意义。
     */

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    /**
     * 拦截方法判断是否重复操作
     * @param joinPoint
     * @return
     */
    @Before("@annotation(com.momoauth.common.security.annotation.ValidateRepeatSubmit)")
    public void Interceptor(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        ValidateRepeatSubmit validateRepeatSubmit = method.getAnnotation(ValidateRepeatSubmit.class);
        HttpServletRequest request = currentRequest();
        String token = request.getHeader("Authorization");
        String redisKey = request.getRequestURI() + token; //缓存中存在该用户请求的URI则视为重复请求
        String redisValue = ""; //空值
        // redisValue默认为空值，也可以自定义传参，但可能实际意义不大
        if (!StringUtils.isBlank(validateRepeatSubmit.name())) {
            redisValue = validateRepeatSubmit.name(); //以name值作为redisValue
        } else if (!StringUtils.isBlank(validateRepeatSubmit.value())) {
            redisValue = validateRepeatSubmit.value(); //以value值作为redisValue
        }
        // 判断防重复操作限时标记是否存在
        if (Boolean.FALSE.equals(redisTemplate.hasKey(redisKey))) {
            // 不存在时则设置防重复操作限时标记
            redisTemplate.opsForValue().set(
                    redisKey,
                    redisValue,
                    validateRepeatSubmit.expireSeconds(),
                    TimeUnit.SECONDS
            );
        } else {
            throw new GlobalException(50000,"访问过于频繁，请稍后再试。");
        }
    }

    private HttpServletRequest currentRequest() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return Optional.ofNullable(servletRequestAttributes).map(ServletRequestAttributes::getRequest).orElse(null);
    }
}
